package simulateOS.entity;

import javafx.scene.control.Alert;
import simulateOS.UI.FileUI;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

public class FAT {
    private Disk disk[] = new Disk[256];
    private Folder c;
    private Path rootPath = new Path("C:",(Path) null);
    private List<Path> paths;
    private Object temp;
    private static FAT fat = null;
    //为初始化的10个可执行文件特殊化处理
    private List<File> fileList = new ArrayList<>();

    //单例，确保FAT独一无二
    public static FAT getFAT(){
        if(fat == null){
            fat = new FAT();
        }
        return fat;
    }

    private FAT(){
        File file = new File("FAT",(String) null,0,(Folder) null);
        this.disk = new Disk[256];
        this.initDisk();
        //磁盘的0、1盘块需要分配给FAT，2盘块给根目录C盘
        disk[0] =new Disk(0,1,"文件",file);
        disk[0].setBegin(true);
        disk[1] = new Disk(1,-1,"文件",file);
        disk[1].setBegin(false);
        this.c = new Folder("C:","root",2,(Folder)null);
        this.disk[2] = new Disk(2, -1, "root", this.c);
        this.disk[2].setBegin(true);

        this.paths = new ArrayList();
        this.paths.add(this.rootPath);
        this.c.setPath(this.rootPath);
        //建立初始的10个可执行文件，内容为空(后期再考虑填充)
        int i;
        for(i = 3;i < 13;i++){
            createExecutableFile("C:",0);
        }
        for(i = 0;i < 10;i++){
            saveFile((File) c.getChildren().get(i),getIo().get(i));
            fileList.add((File) c.getChildren().get(i));
        }
    }

    //查找空盘块,-1则表示找不到空盘块了
    public int searchFreeDisk(){
        int diskNum = -1,i;
        for(i = 3;i < this.disk.length;i++){
            if(disk[i].isFreeBlock()){
                diskNum = i;
                return diskNum;
            }
        }
        return diskNum;
    }

    //创建文本文件
    /**
     * 5,创建失败，无空余盘块可分配!
     * */
    public int createFile(String path,int type){
        String fileName = null;
        int diskNum;
        Folder parent;
        fileName = "新建文本文件";
        diskNum = this.searchFreeDisk();
        if(diskNum == -1){
            return 5;
        }else {
            parent = this.getFolder(path);
            if(parent.hasChildren()){
                fileName = "新建文本文件" + parent.getSumCreate();
            }else {
                fileName = "新建文本文件";
            }
            File newFile = new File(fileName,path,diskNum,parent);
            newFile.setFlag(type);
            if (parent instanceof Folder) {
                parent.addChildren(newFile);
            }
            this.disk[diskNum].allocBlock(-1, "文件", newFile, true);
            newFile.getPoint().add(diskNum);
            newFile.setDiskNum(diskNum);
            newFile.setLength(1);
            Path parentPath = parent.getPath();
            Path thisPath = new Path(path + "\\" + fileName, parentPath);
            if (parentPath != null) {
                parentPath.addChildren(thisPath);
            }
            parent.setSumCreate(parent.getSumCreate() + 1);
            return 1;
        }
    }

    //创建可执行文件
    /**
     * 5,创建失败，无空余盘块可分配!
     * */
    public int createExecutableFile(String path,int type){
        String fileName = null;
        int diskNum;
        Folder parent;
        fileName = "新建可执行文件";
        diskNum = this.searchFreeDisk();
        if(diskNum == -1){
            System.out.println("没有磁盘");
            return 5;
        }else {
            parent = this.getFolder(path);
            if(parent == null){
                System.out.println("非法创建");
                return -1;
            }
            if(parent.hasChildren()){
                fileName = "新建可执行文件" + parent.getSumCreate();
            }else {
                fileName = "新建可执行文件";
            }
            File newFile = new File(fileName,path,diskNum,parent);
            newFile.setFlag(type);
            if (parent instanceof Folder) {
                parent.addChildren(newFile);
            }
            this.disk[diskNum].allocBlock(-1, "文件", newFile, true);
            newFile.getPoint().add(diskNum);
            newFile.setDiskNum(diskNum);
            newFile.setLength(1);
            Path parentPath = parent.getPath();
            Path thisPath = new Path(path + "\\" + fileName, parentPath);
            if (parentPath != null) {
                parentPath.addChildren(thisPath);
            }
            newFile.setExecutableFile(true);
            this.paths.add(thisPath);
            newFile.initList();/*加载记录语句*/
            parent.setSumCreate(parent.getSumCreate() + 1);
            return 1;
        }
    }

    //创建文件夹
    /**
     * 5,创建失败，无空余盘块可分配!
     * 6,创建失败，当前文件夹下的子文件夹已超过8个
     * */
    public int createFolder(String path){
        String folderName = null;
        int diskNum;
        Folder parent;
        folderName = "新建文件夹";
        diskNum = this.searchFreeDisk();
        if (diskNum == -1) {
            return 5;
        } else {
            parent = this.getFolder(path);
            if(parent == null){
                System.out.println("失败");
                return -1;
            }
            if(parent.hasChildren()){
                folderName = "新建文件夹" + parent.getSumCreate();
            }else {
                folderName = "新建文件夹";
            }
            if (parent.getCatalogMaxNum() < 8){
                parent.setCatalogMaxNum(parent.getCatalogMaxNum() + 1);
            }else {
                System.out.println("当前目录下的子目录已超过8个");
                return 6;
            }
            Folder newFolder = new Folder(folderName, path, diskNum, parent);
            if (parent instanceof Folder) {
                parent.addChildren(newFolder);
            }
            this.disk[diskNum].allocBlock(-1, "文件夹", newFolder, true);
            newFolder.setDiskNum(diskNum);
            Path parentPath = parent.getPath();
            Path thisPath = new Path(path + "\\" + folderName, parentPath);
            if (parentPath != null) {
                parentPath.addChildren(thisPath);
            }
            this.paths.add(thisPath);
            newFolder.setPath(thisPath);
            parent.setSumCreate(parent.getSumCreate() + 1);
            newFolder.setSize(0);
            return 1;
        }
    }

    //获取当前路径下的文件夹
    public Folder getFolder(String path) {
        Folder folder = null;
        if(path.equals("C:")){
            folder = this.c;
        }else {
            for(int i = 3; i < this.disk.length; i++) {
                if (!this.disk[i].isFreeBlock() && this.disk[i].getObject() instanceof Folder && ((Folder)((Folder)this.disk[i].getObject())).getPath().getPathName().equals(path)) {
                    folder = (Folder)this.disk[i].getObject();
                    break;
                }
            }
        }
        return folder;
    }

    //重命名
    /**
     * 7，重命名失败，本文件夹内已经有此命名!
     * */
    public int reName(Object object,String newName){
        if(object instanceof Folder){
            if(((Folder) object).hasParent()){
                if(((Folder) object).getParent().hasSameName(newName)){
                    System.out.println("本文件夹内已经有此命名");
                    return 7;
                }else {
                    Path parentPath = ((Folder) object).getParent().getPath();
                    ((Folder) object).setFolderName(newName);
                    Path thisPath = new Path(parentPath.getPathName() + "\\" + ((Folder) object).getFolderName(), parentPath);
                    ((Folder) object).setPath(thisPath);
                }
            }else {
                Path parentPath = ((Folder) object).getParent().getPath();
                ((Folder) object).setFolderName(newName);
                Path thisPath = new Path(parentPath.getPathName() + "\\" + ((Folder) object).getFolderName(), parentPath);
                ((Folder) object).setPath(thisPath);
            }
            return 1;
        }else if(object instanceof File){
            if(((File) object).getParent().hasSameName(newName)){
                System.out.println("本文件夹内已经有此命名");
                return 7;
            }else {
                if(((File) object).isExecutableFile()){
                    newName += ".exe";
                }else {
                    newName += ".txt";
                }
                Path parentPath = ((File) object).getParent().getPath();
                ((File) object).setFileName(newName);
                Path thisPath = new Path(parentPath.getPathName() + "\\" + ((File) object).getFileName(), parentPath);
                if (parentPath != null) {
                    parentPath.addChildren(thisPath);
                }
            }
            return 1;
        }
        return -1;
    }

    //删除文件或文件夹
    /**
     * -1,无法删除,此为C盘!
     * 0,无法删除,文件夹非空!
     * 1,删除成功
     * 2,无法删除,文件已打开!
     * */
    public int delete(Object object){
        Alert alert = null;
        if(object instanceof Folder){
            int num = 0;
            if(((Folder) object).getPath().equals("C:")){
                return -1;
            }
            if(((Folder) object).hasChildren()){
                System.out.println("文件夹非空");
                return 0;
            }
            num = ((Folder) object).getDiskNum();
            disk[num].clearBlock();
            ((Folder) object).getParent().getChildren().remove(object);
            ((Folder) object).getParent().setCatalogMaxNum(((Folder) object).getParent().getCatalogMaxNum() - 1);
            this.paths.remove(this.getPath(((Folder) object).getLocation()));
            return 1;
        }else if(object instanceof File){
            int i;
            if(((File) object).isOpen()){
                return 2;
            }
            if(!((File) object).getPoint().isEmpty()){
                for(i = 0;i < ((File) object).getPoint().size();i++){
                    disk[((File) object).getPoint().get(i)].clearBlock();
                }
                ((File) object).getPoint().clear();
            }
            ((File) object).getParent().getChildren().remove(object);
            return 1;
        }
        return 1;
    }

    //保存文件内容,或是更新文件
    /**
     * 3,保存失败,无空余盘块可分配!
     * 4,保存成功
     * */
    public int saveFile(File file,String str){
        Alert alert = null;
        int lengthOld = file.getLength(),strSize;
        List<String> stringList = getStringList(str);
        if(stringList.isEmpty()){
            strSize = 0;
        }else {
            strSize = stringList.size();
        }
        int lengthNew;
        if(strSize == 0){
            file.setContent(null);
            file.setLength(1);
            if(!file.getPoint().isEmpty()){
                for(int i = 1;i < file.getPoint().size();i++){
                    disk[file.getPoint().get(i)].clearBlock();
                    file.getPoint().remove(file.getPoint().get(i));
                }
                disk[file.getDiskNum()].setIndex(-1);
            }
            file.initList();
            System.out.println("保存成功");
            return 4;
        }
        if(strSize % 64 == 0){
            lengthNew = strSize / 64;
        }else {
            lengthNew = (strSize / 64) + 1;
        }
        if(lengthNew == lengthOld){
            file.setContent(str);
            file.setLength(lengthNew);
            file.initList();
            System.out.println("保存成功");
            return 4;
        }else if(lengthNew < lengthOld){
            int temp = lengthOld - lengthNew;
            if(!file.getPoint().isEmpty()){
                int pl = file.getPoint().size();
                for(int i = pl - temp;i < pl;i++){
                    disk[file.getPoint().get(i)].clearBlock();
                    file.getPoint().remove(file.getPoint().get(i));
                }
                disk[file.getPoint().get(file.getPoint().size() - 1)].setIndex(-1);
                file.setContent(str);
                file.setLength(lengthNew);
                file.initList();
                System.out.println("保存成功");
                return 4;
            }
        }else {
            int temp = lengthNew - lengthOld;
            if(!file.getPoint().isEmpty()){
                int pl = file.getPoint().size();
                for(int i = 0;i < temp;i++){
                    int diskNum = searchFreeDisk();
                    if(diskNum == -1){
                        System.out.println("无空余盘块可分配");
                        System.out.println("保存失败");
                        return 3;
                    }
                    this.disk[diskNum].allocBlock(-1, "文件夹", file, false);
                    disk[file.getPoint().get(pl - 1 + i)].setIndex(diskNum);
                    file.getPoint().add(diskNum);
                }
                file.setContent(str);
                file.setLength(lengthNew);
                file.initList();
                System.out.println("保存成功");
                return 4;
            }
        }
        System.out.println("保存失败");
        return 3;
    }

    //拷贝文件
    public void copy(File file){
        this.setTemp(file);
        System.out.println("复制文件");
    }

    //粘贴文件
    public void paste(String path){
        if(this.getTemp() == null){
            System.out.println("无复制内容");
        }
        if(this.getTemp() instanceof File){
            File file = (File) this.getTemp();
            String fileName = null;
            int diskNum;
            Folder parent;
            parent = this.getFolder(path);
            if(parent == null){
                return;
            }
            if(parent.hasChildren()){
                fileName = file.getFileName() + parent.getChildren().size();
            }else {
                fileName = file.getFileName();
            }
            diskNum = this.searchFreeDisk();
            if(diskNum == -1){
                return;
            }else {
                File newFile = new File(fileName,path,diskNum,parent);
                newFile.setFlag(1);
                if (parent instanceof Folder) {
                    parent.addChildren(newFile);
                }
                this.disk[diskNum].allocBlock(-1, "文件", newFile, true);
                newFile.getPoint().add(diskNum);
                newFile.setDiskNum(diskNum);
                newFile.setLength(1);
                Path parentPath = parent.getPath();
                Path thisPath = new Path(path + "\\" + fileName, parentPath);
                if (parentPath != null) {
                    parentPath.addChildren(thisPath);
                }
                if(saveFile(newFile,file.getContent()) == 4){
                    System.out.println("粘贴成功");
                }else {
                    System.out.println("粘贴失败");
                }
                if(((File) this.getTemp()).isExecutableFile()){
                    newFile.setExecutableFile(true);
                }
                return;
            }
        }
    }

    //打开文件
    public void openFile(File file,int type/*0为只读，1为编辑*/){
        if(file.isOpen()){
            System.out.println("文件已打开");
        }else {
            file.setOpen(true);
            FileUI fileUI = new FileUI(file,type);
            fileUI.getStage().show();
        }
    }

    public void setTemp(File temp) {
        this.temp = temp;
    }

    public Object getTemp() {
        return temp;
    }

    public Folder getC() {
        return c;
    }

    public List<Path> getPaths() {
        return paths;
    }

    public void setPaths(List<Path> paths) {
        this.paths = paths;
    }

    public Path getPath(String path) {
        Iterator var2 = this.paths.iterator();

        Path p;
        do {
            if (!var2.hasNext()) {
                return null;
            }

            p = (Path)var2.next();
        } while(!p.getPathName().equals(path));

        return p;
    }

    public void initDisk(){
        for(int i = 0;i < 256;i++){
            disk[i] = new Disk(i,0,"空",null);
        }
    }

    /**分析当前可执行文件的执行语句
     *
     * @param file
     */
    public List<ExecuteData> analyseExecutableFile(File file){
        List<ExecuteData> executeDataList = new ArrayList<>();
        if(file.getList().isEmpty()){
            executeDataList.add(new ExecuteData(0,0));
            return executeDataList;
        }
        List<String> stringList = file.getList();
        for(String s:stringList){
            String word = s;
            switch (word){
                case "x++":{
                    executeDataList.add(new ExecuteData(2,2));
                    break;
                }
                case "x--":{
                    executeDataList.add(new ExecuteData(3,3));
                    break;
                }
                case "end":{
                    executeDataList.add(new ExecuteData(0,0));
                    break;
                } default:{
                    break;
                }
            }
            for(int i = 0;i < word.length();i++){
                if(word.charAt(0) == 'x'){
                    if(word.length() > 2){
                        if(word.charAt(1) == '='){
                            String num = word.substring(2,word.length());
                            executeDataList.add(new ExecuteData(1,Integer.parseInt(num)));
                            break;
                        }
                    }
                }else if(word.charAt(0) == '!'){
                    if(word.length() > 2){
                        if(word.charAt(1) == 'A'){
                            String num = word.substring(2,word.length());
                            executeDataList.add(new ExecuteData(4,Integer.parseInt(num)));
                            break;
                        }else if(word.charAt(1) == 'B'){
                            String num = word.substring(2,word.length());
                            executeDataList.add(new ExecuteData(5,Integer.parseInt(num)));
                            break;
                        }else if(word.charAt(1) == 'C'){
                            String num = word.substring(2,word.length());
                            executeDataList.add(new ExecuteData(6,Integer.parseInt(num)));
                            break;
                        }else {
                            executeDataList.add(new ExecuteData(0,0));
                            break;
                        }
                    }
                }
            }
        }
        return executeDataList;
    }

    public Disk[] getDisk() {
        return disk;
    }

    private List<String> getIo(){
        List<String> stringList = new ArrayList<>();
        stringList.add("x=0\nx++\nx--\n!A10\nx++\nend\n");
        stringList.add("x=8\nx++\n!B10\nx++\nend\n");
        stringList.add("x=0\nx++\nx=100\n!A8\nx++\nend\n");
        stringList.add("x=10\nx--\nx++\n!C8\nx++\nx++\nend\n");
        stringList.add("x=80\nx++\nx--\n!B7\nx++\nx--\nend\n");
        stringList.add("x=950\nx=800\nx--\n!C10\nx++\n!A8\nx=15\nend\n");
        stringList.add("x=77\nx++\nx--\n!A5\nx++\nx--\nx++\n!B14\nx++\nend\n");
        stringList.add("x=66\nx++\nx--\n!C12\nx++\nend\n");
        stringList.add("x=66\nx++\nx--\n!B10\nx++\nend\n");
        stringList.add("x=99\nx++\nx--\n!C20\nx++\nx--\nx++\n!A10\nx++\nend\n");
        return stringList;
    }

    public List<File> getFileList() {
        return fileList;
    }

    //分析传入的文本内容,按行拆分
    public List<String> getStringList(String str){
        List<String> stringList = new ArrayList<>();
        if(str == null){
            return stringList;
        }
        String sp = "\n";
        String[] TEXTS = str.split(sp);
        if(TEXTS.length > 0){
            for (String s:TEXTS) {
                stringList.add(s);
            }
        }
        return stringList;
    }

    //获取一个随机的可执行文件
    public File getARandomExecuteFile(){
        Random random = new Random();
        int randomNum = random.nextInt(10);
        return getFileList().get(randomNum);
    }

    /**
     * type = -1,无法删除,此为C盘!
     * type = 0,无法删除,文件夹非空!
     * type = 2,无法删除,文件已打开!
     * type = 3,保存失败,无空余盘块可分配!
     * type = 4,保存成功!
     * type = 5,创建失败，无空余盘块可分配!
     * type = 6,创建失败，当前文件夹下的子文件夹已超过8个
     * type = 7,重命名失败，本文件夹内已经有此命名!
     * */
    public void showAlert(int type){
        Alert alert = null;
        if(type == -1){
            alert = new Alert(Alert.AlertType.WARNING);
            alert.setContentText("无法删除,此为C盘!");
            alert.show();
        }else if(type == 0){
            alert = new Alert(Alert.AlertType.WARNING);
            alert.setContentText("无法删除,文件夹非空!");
            alert.show();
        }else if(type == 2){
            alert = new Alert(Alert.AlertType.WARNING);
            alert.setContentText("无法删除,文件已打开!");
            alert.show();
        }else if(type == 3){
            alert = new Alert(Alert.AlertType.WARNING);
            alert.setContentText("保存失败,无空余盘块可分配!");
            alert.show();
        }else if(type == 4){
            alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setContentText("保存成功!");
            alert.show();
        }else if(type == 5){
            alert = new Alert(Alert.AlertType.WARNING);
            alert.setContentText("创建失败，无空余盘块可分配!");
            alert.show();
        }else if(type == 6){
            alert = new Alert(Alert.AlertType.WARNING);
            alert.setContentText("创建失败，当前文件夹下的子文件夹已超过8个!");
            alert.show();
        }else if(type == 7){
            alert = new Alert(Alert.AlertType.WARNING);
            alert.setContentText("重命名失败，本文件夹内已经有此命名!");
            alert.show();
        }
        return;
    }
}
